package org.japo.java.regex.samples;

import java.awt.Color;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.Locale;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import org.japo.java.entities.CodigoCuentaBancaria;
import org.japo.java.entities.Fecha;
import org.japo.java.entities.Transferencia;

/**
 *
 * @author José A. Pacheco Ondoño - joanpaon@gmail.com
 */
public class TransferenciaBancaria extends javax.swing.JFrame {

    // Crea un objeto logger de bitácora
    private static final Logger LOG = Logger.getLogger(TransferenciaBancaria.class.getName());

    // Referencia al modelo
    private Transferencia transferencia = new Transferencia();

    // Fichero de persistencia    
    private final String FICHERO = "transferencia.dat";

    // Semáforos de validación
    private boolean origenOK;
    private boolean destinoOK;
    private boolean fechaOK;
    private boolean importeOK;

    // Expresiones regulares
    private final String ER_ORIGEN = "[0-9]{4}-[0-9]{4}-[0-9]{2}-[0-9]{10}";
    private final String ER_DESTINO = "[0-9]{4}-[0-9]{4}-[0-9]{2}-[0-9]{10}";
    private final String ER_FECHA = "(0[1-9]|[12][0-9]|3[01])/(0[13578]|1[02])/[0-9]+|(0[1-9]|[12][0-9]|30)/(0[469]|11)/[0-9]+|(0[1-9]|1[0-9]|2[0-9])/02/[0-9]+";
    private final String ER_IMPORTE = "(0|[+-]?[1-9][0-9]*)([,\\.][0-9]+)?";

    /**
     * Creates new form TransferenciaBancaria
     */
    public TransferenciaBancaria() {
        initComponents();
        iniciarPosterior();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        pnlOrigen = new javax.swing.JPanel();
        txfOrigen = new javax.swing.JTextField();
        pnlDestino = new javax.swing.JPanel();
        txfDestino = new javax.swing.JTextField();
        pnlFecha = new javax.swing.JPanel();
        txfFecha = new javax.swing.JTextField();
        pnlImporte = new javax.swing.JPanel();
        txfImporte = new javax.swing.JTextField();
        pnlOperacion = new javax.swing.JPanel();
        btnCargar = new javax.swing.JButton();
        btnGuardar = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Transferencia bancaria");
        setResizable(false);

        pnlOrigen.setBorder(javax.swing.BorderFactory.createTitledBorder("Origen"));

        txfOrigen.setFont(new java.awt.Font("Monospaced", 1, 18)); // NOI18N
        txfOrigen.setPreferredSize(new java.awt.Dimension(260, 31));
        txfOrigen.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                txfOrigenFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                txfOrigenFocusLost(evt);
            }
        });

        javax.swing.GroupLayout pnlOrigenLayout = new javax.swing.GroupLayout(pnlOrigen);
        pnlOrigen.setLayout(pnlOrigenLayout);
        pnlOrigenLayout.setHorizontalGroup(
            pnlOrigenLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlOrigenLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfOrigen, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlOrigenLayout.setVerticalGroup(
            pnlOrigenLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlOrigenLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfOrigen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pnlDestino.setBorder(javax.swing.BorderFactory.createTitledBorder("Destino"));

        txfDestino.setFont(new java.awt.Font("Monospaced", 1, 18)); // NOI18N
        txfDestino.setPreferredSize(new java.awt.Dimension(260, 31));
        txfDestino.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                txfDestinoFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                txfDestinoFocusLost(evt);
            }
        });

        javax.swing.GroupLayout pnlDestinoLayout = new javax.swing.GroupLayout(pnlDestino);
        pnlDestino.setLayout(pnlDestinoLayout);
        pnlDestinoLayout.setHorizontalGroup(
            pnlDestinoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlDestinoLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfDestino, javax.swing.GroupLayout.PREFERRED_SIZE, 260, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlDestinoLayout.setVerticalGroup(
            pnlDestinoLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlDestinoLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfDestino, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pnlFecha.setBorder(javax.swing.BorderFactory.createTitledBorder("Fecha"));

        txfFecha.setFont(new java.awt.Font("Monospaced", 1, 18)); // NOI18N
        txfFecha.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                txfFechaFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                txfFechaFocusLost(evt);
            }
        });

        javax.swing.GroupLayout pnlFechaLayout = new javax.swing.GroupLayout(pnlFecha);
        pnlFecha.setLayout(pnlFechaLayout);
        pnlFechaLayout.setHorizontalGroup(
            pnlFechaLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlFechaLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfFecha, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlFechaLayout.setVerticalGroup(
            pnlFechaLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlFechaLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfFecha, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pnlImporte.setBorder(javax.swing.BorderFactory.createTitledBorder("Importe"));

        txfImporte.setFont(new java.awt.Font("Monospaced", 1, 18)); // NOI18N
        txfImporte.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                txfImporteFocusGained(evt);
            }
            public void focusLost(java.awt.event.FocusEvent evt) {
                txfImporteFocusLost(evt);
            }
        });

        javax.swing.GroupLayout pnlImporteLayout = new javax.swing.GroupLayout(pnlImporte);
        pnlImporte.setLayout(pnlImporteLayout);
        pnlImporteLayout.setHorizontalGroup(
            pnlImporteLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlImporteLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfImporte, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        pnlImporteLayout.setVerticalGroup(
            pnlImporteLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlImporteLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(txfImporte, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pnlOperacion.setBorder(javax.swing.BorderFactory.createTitledBorder("Operación"));

        btnCargar.setFont(new java.awt.Font("Calibri", 0, 24)); // NOI18N
        btnCargar.setText("Cargar");
        btnCargar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnCargarActionPerformed(evt);
            }
        });

        btnGuardar.setFont(new java.awt.Font("Calibri", 0, 24)); // NOI18N
        btnGuardar.setText("Guardar");
        btnGuardar.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnGuardarActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout pnlOperacionLayout = new javax.swing.GroupLayout(pnlOperacion);
        pnlOperacion.setLayout(pnlOperacionLayout);
        pnlOperacionLayout.setHorizontalGroup(
            pnlOperacionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlOperacionLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(btnCargar, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addComponent(btnGuardar, javax.swing.GroupLayout.PREFERRED_SIZE, 176, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap())
        );
        pnlOperacionLayout.setVerticalGroup(
            pnlOperacionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(pnlOperacionLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(pnlOperacionLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(btnCargar)
                    .addComponent(btnGuardar))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(pnlOperacion, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
                        .addComponent(pnlOrigen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(pnlFecha, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(pnlDestino, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(pnlImporte, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(pnlOrigen, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(pnlFecha, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(pnlImporte, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(pnlDestino, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(pnlOperacion, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        pack();
        setLocationRelativeTo(null);
    }// </editor-fold>//GEN-END:initComponents

    private void txfOrigenFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfOrigenFocusGained
        // Contenido en edición
        txfOrigen.setForeground(Color.BLACK);

        // Campo seleccionado
        txfOrigen.setBackground(Color.CYAN);
    }//GEN-LAST:event_txfOrigenFocusGained

    private void txfDestinoFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfDestinoFocusGained
        // Contenido en edición
        txfDestino.setForeground(Color.BLACK);

        // Campo seleccionado
        txfDestino.setBackground(Color.CYAN);
    }//GEN-LAST:event_txfDestinoFocusGained

    private void txfFechaFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfFechaFocusGained
        // Contenido en edición
        txfFecha.setForeground(Color.BLACK);

        // Campo seleccionado
        txfFecha.setBackground(Color.CYAN);
    }//GEN-LAST:event_txfFechaFocusGained

    private void txfImporteFocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfImporteFocusGained
        // Contenido en edición
        txfImporte.setForeground(Color.BLACK);

        // Campo seleccionado
        txfImporte.setBackground(Color.CYAN);
    }//GEN-LAST:event_txfImporteFocusGained

    private void txfOrigenFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfOrigenFocusLost
        // Valida el origen
        origenOK = validarCampoTexto(txfOrigen, ER_ORIGEN, "*");

        // Color de fondo de campo no seleccionado
        txfOrigen.setBackground(Color.WHITE);
    }//GEN-LAST:event_txfOrigenFocusLost

    private void txfDestinoFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfDestinoFocusLost
        // Valida el destino
        destinoOK = validarCampoTexto(txfDestino, ER_DESTINO, "*");

        // Color de fondo de campo no seleccionado
        txfDestino.setBackground(Color.WHITE);
    }//GEN-LAST:event_txfDestinoFocusLost

    private void txfFechaFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfFechaFocusLost
        // No hay una ER sencilla que permita validar completamente una fecha
        fechaOK = validarCampoTexto(txfFecha, ER_FECHA, "*");

        // Valida la fecha
        try {
            Fecha fecha = Fecha.parseFecha(txfFecha.getText());
            txfFecha.setText(fecha.toString());
            txfFecha.setForeground(Color.BLACK);
            fechaOK = true;
        } catch (NumberFormatException e) {
            txfFecha.setForeground(Color.RED);
            fechaOK = true;
        }

        // Color de fondo de campo no seleccionado
        txfFecha.setBackground(Color.WHITE);
    }//GEN-LAST:event_txfFechaFocusLost

    private void txfImporteFocusLost(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_txfImporteFocusLost
        // Valida el importe
        importeOK = validarCampoTexto(txfImporte, ER_IMPORTE, "*");

        // Color de fondo de campo no seleccionado
        txfImporte.setBackground(Color.WHITE);

        // Reformatear campo de texto de moneda
        try {
            reformatearCampoMonetario(txfImporte);
        } catch (NumberFormatException nfe) {
            LOG.warning(nfe.toString());
        }
    }//GEN-LAST:event_txfImporteFocusLost

    private void btnCargarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnCargarActionPerformed
        try {
            // Matricula a partir de los datos del fichero
            importarModelo();

            // Carga el interfaz con los datos de la matrícula
            actualizarControl();

            // Comprobar validez de los datos cargados en el interfaz
            comprobarValidez();
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this, "Error al cargar los datos");
        }
    }//GEN-LAST:event_btnCargarActionPerformed

    private void btnGuardarActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btnGuardarActionPerformed
        try {
            if (comprobarValidez()) {
                // Matricula a partir de los datos del interfaz
                actualizarModelo();

                // Guarda los datos en fichero
                exportarModelo();

                // Mensaje de operación correcta
                JOptionPane.showMessageDialog(this, "Datos guardados correctamente");
            } else {
                JOptionPane.showMessageDialog(this, "Hay datos incorrectos.");
            }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this, "Error al guardar los datos.");
        }
    }//GEN-LAST:event_btnGuardarActionPerformed

    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(TransferenciaBancaria.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(TransferenciaBancaria.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(TransferenciaBancaria.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(TransferenciaBancaria.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(() -> {
            new TransferenciaBancaria().setVisible(true);
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btnCargar;
    private javax.swing.JButton btnGuardar;
    private javax.swing.JPanel pnlDestino;
    private javax.swing.JPanel pnlFecha;
    private javax.swing.JPanel pnlImporte;
    private javax.swing.JPanel pnlOperacion;
    private javax.swing.JPanel pnlOrigen;
    private javax.swing.JTextField txfDestino;
    private javax.swing.JTextField txfFecha;
    private javax.swing.JTextField txfImporte;
    private javax.swing.JTextField txfOrigen;
    // End of variables declaration//GEN-END:variables

    private void exportarModelo() throws Exception {
        // Referencias a los cauces a utilizar
        ObjectOutputStream oos = null;
        FileOutputStream fos = null;

        try {
            // Cauce de bytes hacia el fichero
            fos = new FileOutputStream(FICHERO);

            // Cauce de objetos hacia el cauce de bytes
            oos = new ObjectOutputStream(fos);

            // Escribe el objeto
            oos.writeObject(transferencia);
        } finally {
            if (oos != null) {
                // Cierra el cauce de objeto
                oos.close();
            }

            if (fos != null) {
                // Cierra el cauce de fichero
                fos.close();
            }
        }
    }

    private void importarModelo() throws Exception {
        // Referencias a los cauces a utilizar
        ObjectInputStream ois = null;
        FileInputStream fis = null;

        try {
            // Cauce de bytes desde el fichero
            fis = new FileInputStream(FICHERO);

            // Cauce de objetos desde el cauce de bytes
            ois = new ObjectInputStream(fis);

            // Escribe el objeto
            transferencia = (Transferencia) ois.readObject();
        } finally {
            if (ois != null) {
                // Cierra el cauce de objeto
                ois.close();
            }

            if (fis != null) {
                // Cierra el cauce de fichero
                fis.close();
            }
        }
    }

    private void actualizarModelo() throws Exception {
        // Origen
        CodigoCuentaBancaria origen = CodigoCuentaBancaria.
                parseCodigoCuentaBancaria(txfOrigen.getText());

        // Destino
        CodigoCuentaBancaria destino = CodigoCuentaBancaria.
                parseCodigoCuentaBancaria(txfDestino.getText());

        // Fecha
        Fecha fecha = Fecha.parseFecha(txfFecha.getText());

        // Importe
        double importe = Double.parseDouble(txfImporte.getText());

        // Genera la entidad
        transferencia = new Transferencia(origen, destino, fecha, importe);
    }

    private void actualizarControl() {
        // Origen
        txfOrigen.setText(transferencia.getOrigen().toString());

        // Destino
        txfDestino.setText(transferencia.getDestino().toString());

        // Fecha
        txfFecha.setText(transferencia.getFecha().toString());

        // Importe
        txfImporte.setText(transferencia.getImporte() + "");

        // Reformatea el importe
        try {
            reformatearCampoMonetario(txfImporte);
        } catch (NumberFormatException nfe) {
            LOG.warning(nfe.toString());
        }
    }

    private boolean validarCampoTexto(JTextField txfActual, String expReg,
            String textoCampoVacio) throws PatternSyntaxException {
        // Semáforo de validación
        boolean validacionOK = false;

        try {
            // Obtiene el texto del campo
            String textoActual = txfActual.getText().trim();

            // Comprueba campo vacio
            if (textoActual.equals("")) {
                textoActual = textoCampoVacio;
            }

            // Restaura el texto formateado
            txfActual.setText(textoActual);

            // Patrón de la expresión regular
            Pattern patron = Pattern.compile(expReg);

            // Aplica el patrón al texto de prueba
            Matcher detector = patron.matcher(textoActual);

            // Comprueba la coincidencia
            if (detector.matches()) {
                // Contenido correcto
                txfActual.setForeground(Color.BLACK);

                // Actualiza el semáforo
                validacionOK = true;
            } else {
                // Contenido problemático
                txfActual.setForeground(Color.RED);
            }
        } catch (PatternSyntaxException pse) {
            // Contenido problemático
            txfActual.setForeground(Color.RED);

            // Expresión regular errónea - Depurar expresión
            JOptionPane.showMessageDialog(this, "Expresión regular errónea");
        }

        // Devuelve el resultado de la validacion
        return validacionOK;
    }

    private boolean comprobarValidez() {
        // Origen
        origenOK = validarCampoTexto(txfOrigen, ER_ORIGEN, "*");

        // Destino
        destinoOK = validarCampoTexto(txfDestino, ER_DESTINO, "*");

        // No hay una ER sencilla que permita validar completamente una fecha
        fechaOK = validarCampoTexto(txfFecha, ER_FECHA, "*");

        // Valida la fecha
        try {
            Fecha fecha = Fecha.parseFecha(txfFecha.getText());
            txfFecha.setText(fecha.toString());
            txfFecha.setForeground(Color.BLACK);
            fechaOK = true;
        } catch (NumberFormatException e) {
            txfFecha.setForeground(Color.RED);
            fechaOK = true;
        }

        // Importa
        importeOK = validarCampoTexto(txfImporte, ER_IMPORTE, "*");

        // Genera el semaforo general de validación
        return origenOK && destinoOK && fechaOK && importeOK;
    }

    private void iniciarPosterior() {
        // Genera un modelo predeterminado
        transferencia = new Transferencia();

        // Sincroniza el interfaz con el modelo
//        actualizarControl();
        // Comprueba la validez de los datos del interfaz
//        comprobarValidez();
    }

    private void reformatearCampoMonetario(JTextField txfDinero)
            throws NumberFormatException {
        // Obtiene el valor del campo de texto
        String textoDinero = txfDinero.getText();

        // Obtiene el locale por defecto
        Locale l = Locale.getDefault();

        // Sustituye la coma por punto
        if (textoDinero.indexOf(',') >= 0) {
            // Sustituye la coma
            textoDinero = textoDinero.replace(',', '.');
        } else {
            // Actualiza el locale
            l = Locale.ENGLISH;
        }

        // Obtiene la cantidad de dinero
        double dinero = Double.parseDouble(textoDinero);

        // Recalcula el valor introducido al locale
        textoDinero = String.format(l, "%.2f", dinero);

        // Reescribe el valor introducido
        txfDinero.setText(textoDinero);
    }
}
